home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-01-10 | 29.8 KB | 1,297 lines | [TEXT/EDIT] |
- Date: Wed, 20 Oct 1993 22:53:52 -0400 (EDT)
- From: hshubs@BIX.com
- Subject: Unfolder 2.0 source
-
- This is the source code for Unfolder 2.0, so it might be named unfolder20.c,
- and put in the same directory as unfolder20.hqx.
-
- /*
- * The Unfolder - program to reconstitute MacBinary (II) encoded files.
- *
- * by various BIXen in the 'mac.hack/tutorial', started on 25 December 1989
- *
- * Originally written by Don Sample, Howard Shubs, and Bob Perkins on
- * the BYTE Information eXchange (BIX), this program is intended to allow
- * people with a C compiler and no way to transfer resources to their Mac
- * to create a way to deal with Mac files which have been downloaded to
- * non-Macintosh hardware. This program will, when told to Unfold,
- * reconstitute a MacBinary version 1 or 2 file to its original state.
- *
- * The program will work as-is under THINK C 5.0.2, with just the MacTraps
- * and ANSI-small libraries in the project file with it. If you are using
- * other environments, you may need to modify the file. If possible,
- * please use conditional compilation and send a diffs file to Howard Shubs
- * at hshubs@bix.com.
- *
- *
- * #includes
- */
- /*#include "Headers"*/
- #include <stdio.h>
- #include <stdarg.h>
-
- #include <Traps.h>
- #include <Errors.h>
- #include <Types.h>
- #include <GestaltEqu.h>
- #include <OSUtils.h>
- #include <Memory.h>
- #include <Quickdraw.h>
- #include <ToolUtils.h>
- #include <Fonts.h>
- #include <OSEvents.h>
- #include <Menus.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Files.h>
- #include <Resources.h>
- #include <Dialogs.h>
- #include <StandardFile.h>
- #include <Desk.h>
- #include <Finder.h>
- #include <Pascal.h>
- #include <TextEdit.h>
-
-
- /*
- * #defines
- */
-
- #define ALL_TYPES -1L
- #define BASE_RES_ID 400
- #define NIL_POINTER 0L
- #define MOVE_TO_FRONT -1L
- #define REMOVE_ALL_EVENTS 0
- #define MIN_SLEEP 0
- #define NIL_MOUSE_REGION 0L
- #define SUSPEND_RESUME_BIT 0x0001
- #define RESUMING 1
-
- #define APPLE_MENU_ID 128
- #define FILE_MENU_ID 129
- #define EDIT_MENU_ID 130
-
- #define ABOUT_ITEM 1
- #define UNFOLD_ITEM 1
- #define QUIT_ITEM 2
-
- #define MACBINARY_VERSION 129
- #define SCROLL_WIDTH 15
- #define NIL_STRING "\p"
-
- #define NUM_MASTER_BLOCKS 1 /* this number is semi-arbitrary */
-
- #define BF_OWN_APPL 0x0002 /* Some finder info flags not defined */
- #define F_INITED 0x0100 /* in FileMgr.h */
- #define F_CHANGED 0x0200
- #define F_BUSY 0x0400
- /*
- * MacBinary II Header #defines
- */
-
- #define OLD_V_N 0
- #define LEN_F_N 1
- #define FILENAME 2
- #define FILE_TYPE 65
- #define FILE_CREA 69
- #define ORIG_F_FLAGS 73
- #define ZERO_FILL_I 74
- #define FILE_V_POS 75
- #define FILE_H_POS 77
- #define WIN_FOL_ID 79
- #define PROTECTED 81
- #define ZERO_FILL_II 82
- #define LEN_D_FORK 83
- #define LEN_R_FORK 87
- #define F_CREA_DATE 91
- #define F_MOD_DATE 95
- #define LEN_GET_INFO 99
- #define FINDER_FLAGS 101
- #define LEN_TOT_F 116
- #define LEN_SEC_H 120
- #define MBII_VERS_UP 122
- #define MBII_VERS_READ 123
- #define CRC 124
-
- /*
- * Structures
- */
-
- typedef struct Header /* MacBinary header data */
- {
- unsigned char oldVN; /* old version number */
- char fName[64]; /* file name */
- FInfo finderInfo; /* Original Finder information record */
- unsigned char protected;
- long lenDF; /* length of data fork */
- long lenRF; /* length of resource fork */
- long fCreaDate; /* file creation date */
- long fModDate; /* file's last modified date */
- int lenGetInfo; /* length of Get Info comment */
- unsigned char finderFlags; /* Low byte of finder flags */
- long lenTotF; /* length of total files for unpacking */
- int lenSecH; /* length of any secondary header */
- unsigned char mbIIVersUp; /* Version of MB II used for upload */
- unsigned char mbIIVersRead; /* Version of MB II needed to read file */
- int crc;
- } Header;
-
- typedef struct DialogItem /* Dialog item */
- {
- long pointer;
- Rect boundsRect;
- unsigned char itemType;
- unsigned char itemData[3];
- } DialogItem;
-
- typedef struct DialogList /* DITL record */
- {
- short itemCount;
- DialogItem items[2];
- } DialogList;
-
-
- /*
- * Function Prototypes:
- */
-
- void AboutAppl (void);
- /*short int CalcCRC(unsigned char *dataBuf, short int size);*/
- short int CalcCRC(register unsigned char *dataBuf, register int size);
- OSErr CreateFile(Str255 fName, int vRefNum, OSType creator,
- OSType type);
- Rect DeviceRect (void);
- int GetAnEvent(int eventMask, EventRecord *event, long sleep,
- RgnHandle mouseRgn);
- void HandleAppleChoice (short theItem);
- void HandleFileChoice (short theItem);
- void HandleEditChoice (short theItem);
- void HandleEvent (EventRecord *theEvent);
- void HandleMenuChoice (long menuChoice);
- void HandleMouseDown (EventRecord *thisEvent);
- unsigned char HeaderCheck (short int, Header *);
- void Init (void);
- void MessageDialog(char *format, ...);
- void Pause(void);
- void ProcessFile (void);
- void ToolBoxInit(void);
- int TrapAvailable(unsigned trapNumber, int trapType);
- void Unfold (short int refNum, Header *thisHeader,
- SFReply *outputFile);
- int WNEIsImplemented(void);
-
-
- /*
- * Globals
- *
- */
- EventRecord gTheEvent;
- MenuHandle gAppleMenu;
- MenuHandle gFileMenu;
- MenuHandle gEditMenu;
- Point gWhere;
- Boolean gDone;
- Boolean gWNEExists;
- short gQDVersion;
-
-
- /*
- * FUNCTION:
- * ToolBoxInit
- *
- * PURPOSE:
- * Initialize the ToolBox Managers
- */
-
- void ToolBoxInit()
- {
- InitGraf (&(qd.thePort));
- InitFonts ();
- FlushEvents (everyEvent, REMOVE_ALL_EVENTS);
- InitWindows ();
- InitMenus ();
- TEInit ();
- InitDialogs (NIL_POINTER);
- InitCursor ();
- }
-
- /*
- * FUNCTION:
- * Pause
- *
- * PURPOSE:
- * Wait for the user to click the mouse, or to press the return
- * or Enter key.
- */
-
- void Pause()
-
- {
- int button;
- EventRecord myEvent;
-
- button = false;
- while (!button)
- {
- if (GetAnEvent(everyEvent, &myEvent, 0L, NIL_POINTER))
- {
- if (myEvent.what == mouseDown)
- button = true;
- else if (myEvent.what == keyDown)
- {
- if (((myEvent.message & charCodeMask) == 0x0d) ||
- ((myEvent.message & charCodeMask) == 0x03))
- button = true;
- }
- }
- }
- while (StillDown())
- ;
- }
-
- /*
- * FUNCTION:
- * MessageDialog
- *
- * PURPOSE:
- * Display an error message and then pause until the user clicks the
- * mouse button
- *
- * INPUT:
- * char *format - A NULL terminated format string, using
- * the same rules as printf.
- * ... - Other parameters as specified in the
- * format string
- */
-
- void MessageDialog(char *format, ...)
-
- {
- char messageStr[256];
- va_list data;
- OSErr thisErr;
-
- va_start(data, format);
- vsprintf(messageStr, format, data);
- CtoPstr(messageStr);
- ParamText ((ConstStr255Param) messageStr, NIL_STRING, NIL_STRING, NIL_STRING);
- thisErr = CautionAlert (BASE_RES_ID, NIL_POINTER);
- va_end(data);
- }
-
- #define _Unimplemented 0xA89F
- #define _WaitNextEvent 0xA860
-
- /*
- * FUNCTION:
- * GetAnEvent
- *
- * PURPOSE:
- * Get an event from the input queue using whichever is appropriate:
- * GetNextEvent, or WaitNextEvent
- *
- * INPUTS:
- * int eventMask - Types of events to get
- * EventRecord *event - Where to put retreived event
- * long sleep - amount of time to surrender to
- * background tasks
- * RgnHandle mouseRgn - Global region containing mouse.
- *
- * RETURNS:
- * int TRUE if an event was retrieved.
- */
-
- enum /* Which routine to call: Get... or WaitNextEvent */
- {
- notKnown,
- getNext,
- waitNext
- };
-
-
- int GetAnEvent(int eventMask, EventRecord *event, long sleep,
- RgnHandle mouseRgn)
-
- {
- int result;
- static int callRoutine = notKnown;
-
- if (callRoutine == notKnown)
- {
- if (WNEIsImplemented())
- callRoutine = waitNext;
- else
- callRoutine = getNext;
- }
- if (callRoutine == waitNext)
- result = WaitNextEvent(eventMask, event, sleep, mouseRgn);
- else
- {
- SystemTask();
- result = GetNextEvent(eventMask, event);
- }
- return(result);
- }
-
- /*
- * FUNCTION:
- * TrapAvailable
- *
- * PURPOSE:
- * Determine if a specific trap routine is available
- *
- * INPUTS:
- * unsigned tNumber - trap number
- * int tType - trap type (OS or Toolbox)
- *
- * RETURNS:
- * int TRUE if trap is available
- * false otherwise
- */
-
- TrapAvailable(unsigned tNumber, int tType)
-
- {
- /* Check and see if the trap exists. */
-
- return(NGetTrapAddress(tNumber, tType) !=
- GetTrapAddress(_Unimplemented));
- }
-
- /*
- * FUNCTION:
- * WNEIsImplemented
- *
- * PURPOSE:
- * Determine if the WaitNextEvent routine is available
- *
- * RETURNS:
- * int TRUE if WNE is available
- * FALSE otherwise
- */
-
- WNEIsImplemented()
-
- {
-
- SysEnvRec theWorld; /* used to check if machine has new traps */
-
- /*
- * Since WaitNextEvent and HFSDispatch both have the same trap
- * number ($60), we can only call TrapAvailable for WaitNextEvent
- * if we are on a machine that supports separate OS and Toolbox
- * trap tables. We call SysEnvirons and check if machineType < 0.
- */
-
- SysEnvirons(1, &theWorld);
-
- /* Even if we got an error from SysEnvirons, the SysEnvirons glue
- has set up machineType. */
-
- if (theWorld.machineType < 0)
- {
- /* this ROM doesn't have separate trap tables or WaitNextEvent */
- return(false);
- }
- else
- {
- /* check for WaitNextEvent */
- return(TrapAvailable(_WaitNextEvent, ToolTrap));
- }
- }
-
- /*
- * FUNCTION:
- * CreateFile
- *
- * PURPOSE:
- * Create a file, deleting any previous version if necessary.
- *
- * INPUTS:
- * Str255 fName - File name
- * int vRefNum - Directory to create file in
- * OSType creator - File's creator ID
- * OSType type - File type
- *
- * RETURNS:
- * OSErr - noErr if successful.
- */
-
- OSErr CreateFile(Str255 fName, int vRefNum, OSType creator, OSType type)
-
- {
- OSErr thisErr;
-
- thisErr = Create (fName, vRefNum, creator, type);
- if (thisErr == dupFNErr)
- {
- thisErr = FSDelete (fName, vRefNum);
- if (thisErr == noErr)
- thisErr = Create (fName, vRefNum, creator, type);
- }
- return (thisErr);
- }
-
- /*
- * FUNCTION:
- * CalcCRC
- *
- * PURPOSE:
- * Calculate a CCITT CRC for a data buffer
- *
- * INPUTS:
- * unsigned char *data - pointer to data buffer to perform CRC on
- * int size - size of data buffer
- *
- * RETURNS:
- * int - CRC for data buffer. If data buffer contains as its
- * last 2 bytes the CRC for the previous bytes the return
- * value is 0
- */
-
- #define CCITT_CRC_GEN 0x1021
-
- short int CalcCRC(register unsigned char *dataBuf, register int size)
-
- {
- register unsigned short crc = 0;
- register unsigned short dataByte;
- register int i;
-
- while (size--)
- {
- dataByte = *dataBuf++ << 8;
- for (i = 8; i > 0; i--)
- {
- if ((dataByte ^ crc) & 0x8000)
- crc = (crc << 1) ^ CCITT_CRC_GEN;
- else
- crc <<= 1 ;
- dataByte <<= 1;
- }
- }
- return(crc);
- }
-
-
- /*
- * FUNCTION:
- * AboutAppl
- *
- * PURPOSE:
- * Tell about the program
- *
- */
-
- void AboutAppl (void)
- {
- Rect bounds = {58, 108, 192, 400};
- WindowPtr thisWindow;
- GrafPtr oldPort;
-
- GetPort (&oldPort);
- thisWindow = NewWindow (NIL_POINTER, &bounds, "\p", true, 1, (WindowPtr) -1L,
- false, 0L);
- bounds = thisWindow->portRect;
- SetPort (thisWindow);
- /* 123456789 0 123 4 567890123456789 0123456789 */
- TextBox ("Unfolder\015\015by\015\015Howard S Shubs\015Don Sample\015Bob Perkins", 51L, &bounds, 1);
- Pause ();
- SetPort (oldPort);
- DisposeWindow (thisWindow);
- }
-
-
- /*
- * FUNCTION:
- * DeviceRect
- *
- * PURPOSE:
- * Get the bounds rect of the main screen.
- *
- * RETURNS:
- * Rect the bounds rect of the main screen.
- *
- */
-
- Rect DeviceRect (void)
- {
- GDHandle device;
- Rect devRect;
-
- if (gQDVersion > 0)
- {
- device = GetMainDevice ();
- devRect = (**(device)).gdRect;
- }
- else
- devRect = qd.screenBits.bounds;
-
- return devRect;
- }
-
-
- /*
- * FUNCTION:
- * HandleAppleChoice
- *
- * PURPOSE:
- * Deal with selection from the Apple menu
- *
- * INPUTS:
- * short int theItem: contains the selection from the menu
- *
- */
-
- void HandleAppleChoice (short theItem)
- {
- Str255 accName;
- int accNumber;
- short int itemNumber;
- DialogPtr AboutDialog;
-
- switch (theItem)
- {
- case ABOUT_ITEM:
- AboutAppl ();
- break;
- default:
- GetItem (gAppleMenu, theItem, accName);
- accNumber = OpenDeskAcc (accName);
- break;
- }
- }
-
- /*
- * FUNCTION:
- * HandleEditChoice
- *
- * PURPOSE:
- * Deal with selection from the Edit menu by passing them to the
- * system.
- *
- * INPUTS:
- * short int theItem: contains the selection from the menu
- *
- */
-
- void HandleEditChoice (short theItem)
- {
- if (!SystemEdit (theItem - 1))
- ;
- }
-
-
- /*
- * FUNCTION:
- * HandleFileChoice
- *
- * PURPOSE:
- * Deal with selection from the File menu
- *
- * INPUTS:
- * short int theItem: contains the selection from the menu
- *
- */
- /*{}{}{}*/
- void HandleEvent (EventRecord *thisEvent)
- {
- char theChar;
-
- if (gWNEExists)
- WaitNextEvent (everyEvent, thisEvent, MIN_SLEEP, NIL_MOUSE_REGION);
- else
- {
- SystemTask ();
- GetNextEvent (everyEvent, thisEvent);
- }
-
- switch (thisEvent->what)
- {
- case nullEvent:
- break;
- case mouseDown:
- HandleMouseDown (thisEvent);
- break;
- case keyDown:
- case autoKey:
- theChar = (thisEvent->message) & charCodeMask;
- if (( (thisEvent->modifiers) & cmdKey) != 0)
- HandleMenuChoice (MenuKey(theChar));
- break;
- case updateEvt:
- /* BeginUpdate ((WindowPtr) (thisEvent->message) );
- UpdateWindow ((WindowPtr) (thisEvent->message));
- EndUpdate ((WindowPtr) (thisEvent->message) );*/
- break;
- case app4Evt:
- if ( ( (thisEvent->message) & SUSPEND_RESUME_BIT) == RESUMING)
- {
- /* gState.applFlags.isSuspended =
- ((thisEvent->message) & 0x01) == 0;*/
- }
- break;
- }
- }
-
- /*
- * FUNCTION:
- * HandleFileChoice
- *
- * PURPOSE:
- * Deal with selection from the File menu
- *
- * INPUTS:
- * short int theItem: contains the selection from the menu
- *
- */
-
- void HandleFileChoice (short theItem)
- {
- switch (theItem)
- {
- case UNFOLD_ITEM:
- ProcessFile ();
- break;
- case QUIT_ITEM:
- gDone = true;
- break;
- }
- }
-
- /*
- * FUNCTION:
- * HandleMenuChoice
- *
- * PURPOSE:
- * Deal with selection of menu items
- *
- * INPUTS:
- * long int menuChoice: contains the selection from a menu
- *
- * RETURNS:
- * unsigned char - TRUE if the file is MacBinary
- *
- */
-
- void HandleMenuChoice (long menuChoice)
- {
- short theMenu;
- short theItem;
-
- if (menuChoice != 0)
- {
- theMenu = HiWord (menuChoice);
- theItem = LoWord (menuChoice);
- switch (theMenu)
- {
- case APPLE_MENU_ID:
- HandleAppleChoice (theItem);
- break;
- case FILE_MENU_ID:
- HandleFileChoice (theItem);
- break;
- case EDIT_MENU_ID:
- HandleEditChoice (theItem);
- break;
- }
- HiliteMenu (0);
- }
- }
-
- /*
- * FUNCTION:
- * HandleMouseDown
- *
- * PURPOSE:
- * Deal with mouseDown events.
- *
- * INPUTS:
- * EventRecord *thisEvent points to the current event record.
- *
- */
-
- void HandleMouseDown (EventRecord *thisEvent)
- {
- Rect devRect;
- long menuChoice;
- short int thePart;
- WindowPeek window;
- long windSize;
-
- thePart = FindWindow ((thisEvent->where), (WindowPtr *) &window);
- switch (thePart)
- {
- case inMenuBar:
- menuChoice = MenuSelect ((thisEvent->where));
- HandleMenuChoice (menuChoice);
- break;
- case inSysWindow:
- SystemClick (thisEvent, (WindowPtr) window);
- break;
- case inDrag:
- devRect = DeviceRect ();
- DragWindow ((WindowPtr) window, (thisEvent->where), &devRect);
- break;
- case inGrow:
- devRect = DeviceRect ();
- windSize = GrowWindow ((WindowPtr) window, (thisEvent->where),
- &devRect);
- if (windSize > 0)
- {
- Rect bad;
- Point p;
-
- /* invalidate the part of the window with the grow icon */
- bad = (window->port).portRect;
- bad.top = bad.bottom - SCROLL_WIDTH;
- bad.left = bad.right - SCROLL_WIDTH;
- InvalRect (&bad);
- }
- SizeWindow ((WindowPtr) window, LoWord (windSize),
- HiWord (windSize), true);
- break;
- case inGoAway:
- /*if (TrackGoAway ((WindowPtr) window, (thisEvent->where) ) )
- DoCloseWindow ((WindowPtr) window);*/
- break;
- }
- }
-
- /*
- * FUNCTION:
- * HeaderCheck
- *
- * PURPOSE:
- * Look at a selected file to determine if it is a MacBinary (II)
- * file or not.
- *
- * INPUTS:
- * short int refNum - reference number of the opened file to be
- * inspected.
- * Header *thisHeader - MacBinary header record to return data in.
- *
- * RETURNS:
- * unsigned char - TRUE if the file is MacBinary
- *
- */
-
- unsigned char HeaderCheck (short int refNum, Header *thisHeader)
- {
- long int count = 128;
- OSErr thisErr;
- short int i;
- unsigned char *buffer;
- unsigned char soFarSoGood = false;
-
- /* Go to the beginning of the file pointed to by refNum and
- read the first (count) bytes. */
- thisErr = SetFPos (refNum, fsFromStart, 0L);
- if (thisErr == noErr)
- {
- buffer = (unsigned char *) NewPtr (count);
- if ((thisErr = MemError()) == noErr)
- {
- thisErr = FSRead (refNum, &count, buffer);
- if (thisErr == noErr)
- {
- /* Transfer the data read from the file into thisHeader */
- /* First, check to make sure that the mbz bytes ARE zero */
- if (buffer[OLD_V_N] == 0 && buffer[ZERO_FILL_I] == 0)
- soFarSoGood = true;
-
- /* Transfer the file name, and make sure its length is > 0 */
- if (buffer[LEN_F_N] > 0 && buffer[LEN_F_N] < 64 && soFarSoGood)
- {
- BlockMove (&buffer[LEN_F_N], &(thisHeader->fName),
- buffer[LEN_F_N]+1);
-
- /* Get the finderInfo */
- BlockMove (&buffer[FILE_TYPE], &(thisHeader->finderInfo),
- sizeof(FInfo));
-
- /* Get the "protected" flag */
- thisHeader->protected = buffer[PROTECTED];
-
- /* Get the fork sizes */
- BlockMove (&buffer[LEN_D_FORK], &(thisHeader->lenDF),
- 8);
-
- /* Get file's dates */
- BlockMove (&buffer[F_CREA_DATE], &(thisHeader->fCreaDate),
- 8);
-
- /* Get length of "Get Info" comment */
- BlockMove (&buffer[LEN_GET_INFO], &(thisHeader->lenGetInfo),
- 2);
-
- /* Low Finder flags */
- thisHeader->finderFlags = buffer[FINDER_FLAGS];
-
- /* Total size of files */
- BlockMove (&buffer[LEN_TOT_F], &(thisHeader->lenTotF),
- 4);
-
- /* Get length of secondary header */
- BlockMove (&buffer[LEN_SEC_H], &(thisHeader->lenSecH),
- 2);
-
- /* Get the versions of MacBinary II */
- thisHeader->mbIIVersUp = buffer[MBII_VERS_UP];
- thisHeader->mbIIVersRead = buffer[MBII_VERS_READ];
-
- /* Get the CRC of the header */
- BlockMove (&buffer[CRC], &(thisHeader->crc), 2);
-
- soFarSoGood = (CalcCRC(buffer, 124)
- == thisHeader->crc)
- && (buffer[MBII_VERS_READ] == MACBINARY_VERSION);
-
- if (!soFarSoGood && (buffer[ZERO_FILL_II] == 0))
- {
- /* Make more comparisons to make sure that this
- is really a MacBinary I file. */
- for (i = 101; buffer[i]==0 && i < 126; i++);
-
- /* If "i" is >= 126, the loop above completed
- without finding a non-zero, so this is MacBinary I. */
- if (soFarSoGood = i >= 126)
- {
- /* It is, it really _is_ MacBinary I */
-
- /* Low Finder flags */
- thisHeader->finderFlags = 0;
-
- /* Total size of files */
- thisHeader->lenTotF = 0;
-
- /* Get length of secondary header */
- thisHeader->lenSecH = 0;
-
- /* Get the versions of MacBinary II */
- thisHeader->mbIIVersUp = MACBINARY_VERSION;
- thisHeader->mbIIVersRead = MACBINARY_VERSION;
-
- /* Get the CRC of the header */
- thisHeader->crc = 0;
- }
- }
-
- }
- else
- soFarSoGood = false;
- };
- DisposPtr ((Ptr) buffer);
- thisErr = MemError ();
- }
- }
- if (thisErr != noErr)
- MessageDialog("Error: %d reading MacBinary header", thisErr);
- else if (!soFarSoGood)
- MessageDialog("This is not a MacBinary file");
- return soFarSoGood;
- }
-
-
- /*
- * FUNCTION:
- * Unfold
- *
- * PURPOSE:
- * Restore the forks of a MacBinary encoded file.
- *
- * INPUTS:
- * short int refNum - reference number of the opened file to be
- * used as input.
- * Header *thisHeader - MacBinary header information
- * SFReply *thisFile - Information needed to access the created
- * file.
- *
- * RETURNS:
- * unsigned char - TRUE if the file is MacBinary
- * Header *thisHeader - MacBinary header record to return data in.
- *
- */
-
- void Unfold (short int refNum, Header *thisHeader, SFReply *thisFile)
- {
- char *buffer;
- char bufferAllocated;
- long int buffSize;
- long int forkSize;
- long int offSet;
- /* long int grow;*/
- short int outRefNum; /* reference number for the output file */
- OSErr thisErr; /* status code */
-
- /* Allocate memory for a buffer by this rule:
- Never allocate less than MIN_BUFFER, or more than MAX_BUFFER.
- Between those two, allocate what's available less LEAVE_FREE,
- as long as that isn't less than MIN_BUFFER. */
- #define MIN_BUFFER 4*1024L
- #define MAX_BUFFER 256*1024L
- #define LEAVE_FREE 32*1024L
- buffSize = MaxBlock (); /*MaxMem (&grow);*/
- buffSize = buffSize > MAX_BUFFER + LEAVE_FREE ?
- MAX_BUFFER :
- buffSize < MIN_BUFFER ?
- MIN_BUFFER :
- buffSize - LEAVE_FREE < MIN_BUFFER ?
- MIN_BUFFER :
- buffSize - LEAVE_FREE;
-
- buffer = NewPtr (buffSize);
- bufferAllocated = (thisErr = MemError()) == noErr;
-
- if (!bufferAllocated)
- MessageDialog ("Couldn't allocate a work buffer. Give this program more memory, then run it again.");
-
- /* Is there a data fork? If there is, rebuild it. */
- if ((thisHeader->lenDF > 0) && bufferAllocated)
- {
- Ptr source;
- Size count;
- Str255 dest;
-
- source = (Ptr) &((*thisFile).fName);
- count = (char) *source;
- count = BitAnd (count, 0x000000ffL) + 1L;
- BlockMove (source, dest, count); /* {}{}{} */
-
- forkSize = thisHeader->lenDF;
- if ((thisErr = FSOpen (dest, thisFile->vRefNum, &outRefNum))
- == noErr)
- {
- /* position beyond the MacBinary header */
- if ((thisErr = SetFPos (refNum, fsFromStart, 128)) == noErr)
- {
- while (thisErr == noErr && forkSize > buffSize)
- {
- thisErr = FSRead (refNum, &buffSize, buffer);
- if (thisErr == noErr)
- thisErr = FSWrite (outRefNum, &buffSize, buffer);
- forkSize -= buffSize;
- }
- if (thisErr == noErr)
- {
- thisErr = FSRead(refNum, &forkSize, buffer);
- if (thisErr == noErr)
- thisErr = FSWrite (outRefNum, &forkSize, buffer);
- }
- }
- if (thisErr == noErr)
- {
- thisErr = FSClose (outRefNum);
- if (thisErr == noErr)
- thisErr = FlushVol (NIL_POINTER, thisFile->vRefNum);
- else
- FlushVol (NIL_POINTER, thisFile->vRefNum);
- }
- else
- {
- FSClose (outRefNum);
- FlushVol (NIL_POINTER, thisFile->vRefNum);
- }
- }
- }
-
- /* Is there a resource fork? If there is, rebuild it. */
- if ((thisHeader->lenRF > 0) && bufferAllocated)
- {
- Ptr source;
- Size count;
- Str255 dest;
-
- source = (Ptr) &((*thisFile).fName);
- count = (char) *source;
- count = BitAnd (count, 0x000000ffL) + 1L;
- BlockMove (source, dest, count); /* {}{}{} */
-
- forkSize = thisHeader->lenRF;
- if ((thisErr = OpenRF (dest, thisFile->vRefNum, &outRefNum))
- == noErr)
- {
- /* position beyond the MacBinary header and the Data Fork */
- offSet = (128 - (thisHeader->lenDF % 128)) & 0x7f;
- if ((thisErr = SetFPos (refNum, fsFromStart,
- (thisHeader->lenDF) + offSet + 128)) == noErr)
- {
- while (thisErr == noErr && forkSize > buffSize)
- {
- thisErr = FSRead (refNum, &buffSize, buffer);
- if (thisErr == noErr)
- thisErr = FSWrite (outRefNum, &buffSize, buffer);
- forkSize -= buffSize;
- }
- if (thisErr == noErr)
- {
- thisErr = FSRead(refNum, &forkSize, buffer);
- if (thisErr == noErr)
- thisErr = FSWrite (outRefNum, &forkSize, buffer);
- }
- }
- if (thisErr == noErr)
- {
- thisErr = FSClose (outRefNum);
- if (thisErr == noErr)
- thisErr = FlushVol (NIL_POINTER, thisFile->vRefNum);
- else
- FlushVol (NIL_POINTER, thisFile->vRefNum);
- }
- else
- {
- FSClose (outRefNum);
- FlushVol (NIL_POINTER, thisFile->vRefNum);
- }
- }
- }
- if (bufferAllocated)
- DisposPtr (buffer);
- if (thisErr != noErr)
- MessageDialog("Error: %d unfolding MacBinary file", thisErr);
- }
-
-
- /*
- * FUNCTION:
- * ProcessFile
- *
- * PURPOSE:
- * Determine our input and output files, then do the processing.
- *
- */
-
- void ProcessFile (void)
- {
- Boolean running;
- int i;
- SFTypeList typeList;
- SFReply inputFile, outputFile;
- Header mbHeader;
- OSErr thisErr;
- short int refNum;
- ParamBlockRec paramBlock;
- unsigned int finderFlags;
-
- SFGetFile (gWhere, NIL_POINTER, NIL_POINTER, ALL_TYPES, typeList,
- NIL_POINTER, &inputFile);
- running = inputFile.good == true;
-
- if (running)
- {
- if ((thisErr = FSOpen (inputFile.fName, inputFile.vRefNum,
- &refNum)) != noErr)
- {
- PtoCstr((unsigned char *) inputFile.fName);
- MessageDialog("Error: %d opening file %s", thisErr, inputFile.fName);
- }
-
- /* read the MacBinary header. If it's okay, decode the file. */
- else if (HeaderCheck (refNum, &mbHeader))
- {
- Str255 *string = (Str255 *) &(mbHeader.fName);
-
- SFPutFile (gWhere, NIL_POINTER, *string,
- NIL_POINTER, &outputFile);
- if (outputFile.good)
- {
- if ((thisErr = CreateFile(outputFile.fName,
- outputFile.vRefNum, mbHeader.finderInfo.fdCreator,
- mbHeader.finderInfo.fdType)) != noErr)
- {
- PtoCstr((unsigned char *) outputFile.fName);
- MessageDialog("Error: %d creating file %s", thisErr,
- outputFile.fName);
- running = false;
- }
- else
- {
- /* copy data & resource forks from input file */
- Unfold (refNum, &mbHeader, &outputFile);
-
- paramBlock.fileParam.ioCompletion = NIL_POINTER;
- paramBlock.fileParam.ioNamePtr = (StringPtr) &outputFile.fName;
- paramBlock.fileParam.ioVRefNum = outputFile.vRefNum;
- paramBlock.fileParam.ioFVersNum = 0;
- /* Set the finder Info for the file */
- paramBlock.fileParam.ioFlFndrInfo = mbHeader.finderInfo;
- finderFlags = mbHeader.finderInfo.fdFlags;
- finderFlags |= mbHeader.finderFlags;
- finderFlags &= ~(fOnDesk | BF_OWN_APPL | F_INITED |
- F_CHANGED | F_BUSY);
- paramBlock.fileParam.ioFlFndrInfo.fdFlags = finderFlags;
- paramBlock.fileParam.ioFlFndrInfo.fdFldr = 0;
- paramBlock.fileParam.ioFlFndrInfo.fdLocation.h = 0;
- paramBlock.fileParam.ioFlFndrInfo.fdLocation.v = 0;
- /* Set the Creation and Modification dates on the file */
- paramBlock.fileParam.ioFlCrDat = mbHeader.fCreaDate;
- paramBlock.fileParam.ioFlMdDat = mbHeader.fModDate;
- thisErr = PBSetFInfo (¶mBlock, false);
- if (thisErr != noErr)
- MessageDialog("Error: %d, setting file attributes", thisErr);
- }
- }
- }
- thisErr = FSClose (refNum);
- }
- }
-
-
- /*
- * FUNCTION:
- * Init
- *
- * PURPOSE:
- * Initialize the environment, establish menus, and set variables.
- *
- * SIDE EFFECTS:
- * Initializes the environment, establishes menus, and initializes
- * the global variables.
- *
- */
-
- void Init (void)
- {
- long response;
- Boolean gestaltExists;
- Boolean sysEnvironsExists;
- SysEnvRec *theWorld;
- OSErr thisErr;
- Handle thisHandle;
- DialogList errorDITL;
- AlertTemplate thisAlert;
-
-
- /* Initialize everything */
- /* Init the toolbox routines */
- ToolBoxInit();
-
- /* Make menus */
- gAppleMenu = NewMenu (APPLE_MENU_ID, "\p\024");
- gFileMenu = NewMenu (FILE_MENU_ID, "\pFile");
- gEditMenu = NewMenu (EDIT_MENU_ID, "\pEdit");
- InsertMenu (gAppleMenu, 0);
- InsertMenu (gFileMenu, 0);
- InsertMenu (gEditMenu, 0);
-
- /* Add items to menus */
- AppendMenu (gAppleMenu, "\pAbout Unfolder...;(-");
- AddResMenu (gAppleMenu, 'DRVR');
- AppendMenu (gFileMenu, "\pUnfold.../U;Quit/Q");
- AppendMenu (gEditMenu, "\pUndo/Z;(-;Cut/X;Copy/C;Paste/X;Clear");
-
- /* Draw the menu bar */
- DrawMenuBar ();
-
- /* Specify the point at which the SF dialogs will appear */
- gWhere.v = 100;
- gWhere.h = 100;
-
- /* We're not done yet */
- gDone = false;
-
- /* Can we call WaitNextEvent? */
- gWNEExists = WNEIsImplemented();
-
- /* What kind of Quickdraw do we have? */
- gestaltExists = TrapAvailable (_GestaltDispatch, ToolTrap);
- sysEnvironsExists = TrapAvailable (_SysEnvirons, OSTrap);
- if (gestaltExists)
- thisErr = Gestalt ('qd ', &response);
- else
- {
- if (sysEnvironsExists)
- {
- theWorld = (SysEnvRec *) NewPtr (sizeof (SysEnvRec));
- if (theWorld == NIL_POINTER)
- {
- thisErr = MemError ();
- MessageDialog("Error: %d allocating memory", thisErr);
- }
- thisErr = SysEnvirons (1, theWorld);
- response = (long) theWorld->hasColorQD;
- DisposPtr ((Ptr) theWorld);
- }
- else
- response = 0L;
- }
- gQDVersion = LoWord (response) >> 8;
-
-
- /* Do the miscellaneous resources exist yet? Check for one. If
- that doesn't exist, assume that none of them do and create them. */
- thisHandle = GetResource ('ALRT', BASE_RES_ID);
- if (thisHandle == NIL_POINTER)
- {
- /* Construct the error DITL see IM I-427 */
- errorDITL.itemCount = 1; /* total of two items */
-
- /* OK button */
- errorDITL.items[0].pointer = 0L;
- errorDITL.items[0].boundsRect.top = 96;
- errorDITL.items[0].boundsRect.left = 137;
- errorDITL.items[0].boundsRect.bottom = 116;
- errorDITL.items[0].boundsRect.right = 195;
- errorDITL.items[0].itemType = (char) btnCtrl | ctrlItem;
- errorDITL.items[0].itemData[0] = 2;
- errorDITL.items[0].itemData[1] = 'O';
- errorDITL.items[0].itemData[2] = 'K';
-
- /* Static Text */
- errorDITL.items[1].pointer = 0L;
- errorDITL.items[1].boundsRect.top = 13;
- errorDITL.items[1].boundsRect.left = 65;
- errorDITL.items[1].boundsRect.bottom = 82;
- errorDITL.items[1].boundsRect.right = 318;
- errorDITL.items[1].itemType = (char) statText;
- errorDITL.items[1].itemData[0] = 2;
- errorDITL.items[1].itemData[1] = '^';
- errorDITL.items[1].itemData[2] = '0';
-
- /* Make the DITL into a resource */
- thisHandle = NewHandle (sizeof (DialogList));
- BlockMove (&errorDITL, *thisHandle, sizeof (DialogList));
- AddResource (thisHandle, 'DITL', BASE_RES_ID, "\pError DITL");
- thisErr = ResError ();
-
-
- /* Construct the error ALRT IM-I 426 */
- thisAlert.boundsRect.top = 40;
- thisAlert.boundsRect.left = 40;
- thisAlert.boundsRect.bottom = 172;
- thisAlert.boundsRect.right = 368;
- thisAlert.itemsID = BASE_RES_ID;
- thisAlert.stages = 0x7775;
-
- /* Make the ALRT into a resource */
- thisHandle = NewHandle (sizeof (AlertTemplate));
- BlockMove (&thisAlert, *thisHandle, sizeof (AlertTemplate));
- AddResource (thisHandle, 'ALRT', BASE_RES_ID, "\pError ALRT");
- thisErr = ResError ();
- }
- else
- ReleaseResource (thisHandle);
- }
-
-
- main()
- {
- int i;
-
- /* Maximize available memory */
- MaxApplZone ();
-
- /* Be sure to have plenty of master pointer blocks */
- for (i = 0; i < NUM_MASTER_BLOCKS; i++)
- MoreMasters();
-
- Init ();
-
- while (!gDone)
- {
- HandleEvent (&gTheEvent);
- }
-
- } /* main */
-
-